using B.S.Databasic.Api.Read.Application.Command.Account;
using B.S.Databasic.Api.Read.Common;
using B.S.Databasic.Domain.RBAC;
using B.S.Databasic.ErrorCode;
using B.S.Databasic.Infrastructure.Interface;
using MediatR;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace B.S.Databasic.Api.Read.Application.Handler.Account
{
    public class LoginHandler : IRequestHandler<LoginCommand, ApiResult<AccountLoginDTO>>
    {
        private readonly IBaseRepository<AccountModel> _accountRepo;
        private readonly IBaseRepository<AccountRoleModel> _accountRoleRepo;
        private readonly IBaseRepository<RoleModel> _roleRepo;
        private readonly IConfiguration _configuration;
        private readonly ILogger<LoginHandler> _logger;

        public LoginHandler(
            IBaseRepository<AccountModel> accountRepo,
            IBaseRepository<AccountRoleModel> accountRoleRepo,
            IBaseRepository<RoleModel> roleRepo,
            IConfiguration configuration,
            ILogger<LoginHandler> logger)
        {
            _accountRepo = accountRepo;
            _accountRoleRepo = accountRoleRepo;
            _roleRepo = roleRepo;
            _configuration = configuration;
            _logger = logger;
        }

        public async Task<ApiResult<AccountLoginDTO>> Handle(LoginCommand request, CancellationToken cancellationToken)
        {
            var res = new ApiResult<AccountLoginDTO>();
                var user = _accountRepo.GetAll().FirstOrDefault(x => !x.IsDeleted && x.Name == request.Name && x.Pwd == request.Pwd);
                if (user == null)
                {
                    res.Msg = "账号或密码错误";
                    res.Code = ApiEnum.Error;
                    res.Data = null;
                    return await Task.FromResult(res);
                }
                if (!user.IsState)
                {
                    res.Msg = "账号已被禁用";
                    res.Code = ApiEnum.Error;
                    res.Data = null;
                    return await Task.FromResult(res);
                }
                var accountRoles = _accountRoleRepo.GetAll().Where(x => !x.IsDeleted && x.AccountId == user.Id).ToList();
                var roleIds = accountRoles.Select(x => x.RoleId).ToList();
                var roleNames = _roleRepo.GetAll().Where(x => !x.IsDeleted && roleIds.Contains(x.Id)).Select(x => x.RoleName).ToList();
                var dto = new AccountDTO
                {
                    Id = user.Id,
                    Name = user.Name,
                    RealName = user.RealName,
                    IsState = user.IsState,
                    CreateTime = user.CreateTime,
                    RoleIds = roleIds,
                    RoleName = roleNames
                };
                _logger.LogInformation($"在{DateTime.Now}用户{request.Name}登录成功");
                res.Msg = "登录成功";
                res.Code = ApiEnum.Success;
                res.Data = new AccountLoginDTO { accMsg = dto, ToKen = CreateTokenString(user.Id, user.Name, "1") };
                return await Task.FromResult(res);
        }
        /// <summary>
        /// 生成 JWT Token（令牌）
        /// </summary>
        /// <returns></returns>
        private string CreateTokenString(long Uid, string? Name, string? RoleId)
        {
            var jwtSettings = _configuration.GetSection("JwtSettings").Get<JwtSettings>();
            //私钥
            var secretByte = Encoding.UTF8.GetBytes(jwtSettings.SigningKey);
            // 非对称加密
            var signingKey = new SymmetricSecurityKey(secretByte);
            // 使用256 生成数字签名
            var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
            
            // 获取用户真实姓名
            var user = _accountRepo.GetAll().FirstOrDefault(x => x.Id == Uid);
            var realName = user?.RealName ?? Name;
            
            //Claims 指用户信息 用户名 用户ID 角色ID 真实姓名
            var claims = new[] {
                new Claim("UserId",Uid.ToString()),
                new Claim("UserName",Name),
                new Claim("RoleId",RoleId),
                new Claim("RealName",realName),
            };
            // 生成Token
            var token = new JwtSecurityToken(
                issuer: jwtSettings.Issuer,
                audience: jwtSettings.Audience,
                expires: DateTime.Now.AddMinutes(jwtSettings.AccessTokenExpirationMinutes), // 分钟
                signingCredentials: signingCredentials,
                claims: claims
            );
            // 生成token 字符串
            var strToken = new JwtSecurityTokenHandler().WriteToken(token);
            return strToken;
        }
    }
}